package com.runa.monitor.platinterface.extend.equ;

import com.google.protobuf.ByteString;
import com.runa.monitor.comm.constants.ResultConstants;
import com.runa.monitor.platinterface.backwork.impl.EquInstructTaskFunction;
import com.runa.monitor.platinterface.dispatch.grpcComm.ResultComm;
import com.runa.monitor.platinterface.netservice.connect.commstatus.CommStatus;
import com.runa.monitor.platinterface.netservice.equipment.NetEqu;
import com.runa.monitor.platinterface.platService.NetEquService;
import com.runa.persistence.StringUtil;
import com.runa.persistence.service.InvokeService;
import com.runa.persistence.util.LogUtil;
import com.runa.protocol.util.ByteUtil;
import com.runa.rccprotocol.dto.ConcentratorRequestData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 2024/9/20 11:40
 * zhangYB
 */
@Slf4j
@Service
public class EquInstructService {

    @Resource
    private NetEquService netEquService;

    private AtomicLong count = new AtomicLong(0);

    private AtomicBoolean executeF = new AtomicBoolean(false);

    private static Map<String, EquInstructRequest> requestMap = new ConcurrentHashMap<>();

    private static String TASK_NAME = "task";
    private static String FOLDER_NAME = "INSTRUCT";

    public void execute() {
        if (executeF.get()) {
            return;
        }
        if (!executeF.compareAndSet(false, true)) {
            return;
        }
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    if (requestMap.isEmpty()) {
                        return;
                    }
                    for (String netSerial : requestMap.keySet()) {
                        EquInstructRequest request = requestMap.get(netSerial);
                        try {
                            if (request.isAlreadySend()) {
                                EquInstruct equInstruct = request.getEquInstruct();
                                if (System.currentTimeMillis() - request.getSendStartTime() > equInstruct.getTimeout()) {
                                    // 超时
                                    finish(netSerial, CommStatus.TimeOut);
                                }
                            }
                        } catch (Exception e) {
                            log.error("", e);
                        }
                    }
                } catch (Exception e) {
                    log.error("EquInstructService.execute timer.schedule: ", e);
                }
            }
        }, 0, 100);

    }

    public Object request(EquInstruct equInstruct) {
        try {
            String netEquSerial = equInstruct.getNetEquSerial();
            NetEqu<String> netEqu = netEquService.getNetEquBySerialCache(netEquSerial);
            if (null != netEqu) {
                if (netEqu.online()) {
                    EquInstructRequest equInstructRequest = new EquInstructRequest(netEquSerial);
                    equInstructRequest.setEquInstruct(equInstruct);
                    equInstructRequest.setData(ByteUtil.hexStringToByte(equInstruct.getInstruct()));
                    equInstructRequest.setRemain(equInstruct);
                    log.info("{} 请求指令: {}", netEquSerial, equInstruct.getInstruct());
                    if (StringUtil.isBlank(equInstruct.getTaskNo())) {
                        equInstruct.setTaskNo("t"+count.incrementAndGet());
                    }
                    EquInstructTaskFunction taskFunction = new EquInstructTaskFunction(netEquSerial);
                    taskFunction.setPriority(equInstruct.getPriority());
                    netEqu.sendRequest(equInstructRequest, taskFunction);
                    requestMap.put(netEquSerial, equInstructRequest);
                    execute();
                    return ResultComm.newBuilder().setCode(ResultConstants.CODE_200).setMsg("成功[task="+equInstruct.getTaskNo()+"]").build();
                } else {
                    log.error("集中器: {} 不在线", netEquSerial);
                    return ResultComm.newBuilder().setCode(ResultConstants.CODE_500).setMsg("集中器不在线").build();
                }
            } else {
                log.error("未找到集中器: {}", netEquSerial);
                return ResultComm.newBuilder().setCode(ResultConstants.CODE_500).setMsg("未找到集中器").build();
            }
        } catch (Exception e) {
            log.error("EquInstructService.request error: ", e);
            return ResultComm.newBuilder().setCode(ResultConstants.CODE_500).setMsg("EquInstructService.request error:" + e.getMessage()).build();
        }
    }

    public static void start(String netSerial, ConcentratorRequestData request) {
        try {
            if (StringUtil.isBlank(netSerial) || null == request) {
                return;
            }
            EquInstructRequest equInstructRequest = requestMap.get(netSerial);
            if (null == equInstructRequest) {
                return;
            }
            LogUtil.getLogAndInfo(TASK_NAME, FOLDER_NAME, "{} 已发送: {}", netSerial, ByteUtil.byteToHexString(request.getData()));
            equInstructRequest.setSendStartTime(System.currentTimeMillis());
            equInstructRequest.setAlreadySend(true);
        } catch (Exception e) {
            log.error("", e);
        }
    }


    public static void receive(String netSerial, String message) {
        try {
            if (StringUtil.isBlank(netSerial) || StringUtil.isBlank(message)) {
                return;
            }
            EquInstructRequest equInstructRequest = requestMap.get(netSerial);
            if (null == equInstructRequest) {
                return;
            }
            LogUtil.getLogAndInfo(TASK_NAME, FOLDER_NAME, "{} 收到: {}", netSerial, message);
            equInstructRequest.getResponses().add(message);
        } catch (Exception e) {
            log.error("", e);
        }
    }

    public static void finish(String netSerial, CommStatus status) {
        try {
            EquInstructRequest equInstructRequest = requestMap.remove(netSerial);
            if (null == equInstructRequest) {
                return;
            }
            LogUtil.getLogAndInfo(TASK_NAME, FOLDER_NAME, "{} 结束: {}", netSerial, status);
            EquInstruct equInstruct = equInstructRequest.getEquInstruct();
            if (null != equInstruct) {
                InvokeService.saveInstructLog(equInstruct.getTaskNo(), netSerial, status.name(), equInstruct.getInstruct()
                        , equInstructRequest.getResponses());
            }
        } catch (Exception e) {
            log.error("", e);
        }
    }





}
